#include "EffectPosition3NormalColor.h"

#pragma region Constructor/Desctructor
EffectPosition3NormalColor::EffectPosition3NormalColor()
{
}
EffectPosition3NormalColor::~EffectPosition3NormalColor()
{
}
#pragma endregion

#pragma region Public functions
#pragma region Virtual function definitions
void EffectPosition3NormalColor::Initialize(HWND WindowHandle, HINSTANCE hInstance, ID3D11Device* Device, ID3D11DeviceContext* DeviceContext)
{
	D3DDevice = Device;
	D3DDeviceContext = DeviceContext;

	ID3DBlob* VSBlob = nullptr;
	ID3DBlob* PSBlob = nullptr;

	CompileShaderFromFile( L"Position3NormalColor.fx", "VS", "vs_4_0", &VSBlob );
	CompileShaderFromFile( L"Position3NormalColor.fx", "PS", "ps_4_0", &PSBlob );

	D3DDevice->CreateVertexShader( VSBlob->GetBufferPointer(), VSBlob->GetBufferSize(), nullptr, &VertexShader );
	D3DDevice->CreatePixelShader( PSBlob->GetBufferPointer(), PSBlob->GetBufferSize(), nullptr, &PixelShader );

    D3D11_INPUT_ELEMENT_DESC layout[] =
    {
        { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
        { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
        { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0 },
	};
	UINT numElements = ARRAYSIZE(layout);

	D3DDevice->CreateInputLayout( layout, numElements, VSBlob->GetBufferPointer(), VSBlob->GetBufferSize(), &VertexLayout );
}
void EffectPosition3NormalColor::Update(int DeltaTime)
{

}
void EffectPosition3NormalColor::Shutdown()
{
	if (VertexShader)
	{
		VertexShader->Release();
		VertexShader = 0;
	}
	if (PixelShader)
	{
		PixelShader->Release();
		PixelShader = 0;
	}
	if (VertexBuffer)
	{
		VertexBuffer->Release();
		VertexBuffer = 0;
	}
	if (VertexLayout)
	{
		VertexLayout->Release();
		VertexLayout = 0;
	}
	if (ConstantBuffer)
	{
		ConstantBuffer->Release();
		ConstantBuffer = 0;
	}
	Vertices.clear();
}
void EffectPosition3NormalColor::Render()
{
	UINT stride = sizeof(Position3NormalColor);
	UINT offset = 0;
	D3DDeviceContext->VSSetConstantBuffers( 0, 1, &ConstantBuffer );
	D3DDeviceContext->IASetVertexBuffers( 0, 1, &VertexBuffer, &stride, &offset );
	D3DDeviceContext->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );
	D3DDeviceContext->IASetInputLayout(VertexLayout);
	D3DDeviceContext->VSSetShader( VertexShader, nullptr, 0 );
	D3DDeviceContext->PSSetShader( PixelShader, nullptr, 0 );
	D3DDeviceContext->Draw(Vertices.size(),0);
}
#pragma endregion

#pragma region Normal functions
void EffectPosition3NormalColor::AddVertex(Position3NormalColor Vertex)
{
	Vertices.push_back(Vertex);
}
void EffectPosition3NormalColor::Create()
{
	D3D11_BUFFER_DESC bd;
	ZeroMemory(&bd, sizeof(bd));

    bd.Usage = D3D11_USAGE_DEFAULT;
    bd.ByteWidth = sizeof( Position3NormalColor ) * Vertices.size();
    bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
	bd.CPUAccessFlags = 0;
    D3D11_SUBRESOURCE_DATA InitData;
	ZeroMemory( &InitData, sizeof(InitData) );
    InitData.pSysMem = Vertices.data();
    D3DDevice->CreateBuffer( &bd, &InitData, &VertexBuffer );

	// Create the constant buffer
	bd.Usage = D3D11_USAGE_DEFAULT;
	bd.ByteWidth = sizeof(ConstantBufferStruct);
	bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
	bd.CPUAccessFlags = 0;
    D3DDevice->CreateBuffer( &bd, nullptr, &ConstantBuffer );
}
ID3D11Buffer* EffectPosition3NormalColor::GetConstantBuffer()
{
	return ConstantBuffer;
}
#pragma endregion
#pragma endregion

#pragma region Private functions
void EffectPosition3NormalColor::CompileShaderFromFile( WCHAR* szFileName, LPCSTR szEntryPoint, LPCSTR szShaderModel, ID3DBlob** ppBlobOut )
{
    HRESULT hr = S_OK;

    DWORD dwShaderFlags = D3DCOMPILE_ENABLE_STRICTNESS;
#if defined( DEBUG ) || defined( _DEBUG )
    // Set the D3DCOMPILE_DEBUG flag to embed debug information in the shaders.
    // Setting this flag improves the shader debugging experience, but still allows 
    // the shaders to be optimized and to run exactly the way they will run in 
    // the release configuration of this program.
    dwShaderFlags |= D3DCOMPILE_DEBUG;
#endif

    ID3DBlob* pErrorBlob = nullptr;
    hr = D3DCompileFromFile( szFileName, nullptr, nullptr, szEntryPoint, szShaderModel, 
        dwShaderFlags, 0, ppBlobOut, &pErrorBlob );
    if( FAILED(hr) )
    {
        if( pErrorBlob )
		{
            OutputDebugStringA( reinterpret_cast<const char*>( pErrorBlob->GetBufferPointer() ) );
            pErrorBlob->Release();
        }
    }
    if( pErrorBlob ) pErrorBlob->Release();
}
#pragma endregion